package typejump;
import java.io.File;
import java.io.FileInputStream;
import java.io.PrintStream;
import java.io.InputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;

import typejump.engine.GameEngine;
import typejump.objects.*;

public class GameIO {
	
	public static String loadLevel(String name) { return loadFile("levels/" + name); }
	public static String loadSave(String name) { return loadFile("saves/" + name); }
	
	public static String loadFile(String name) {
		File file = InstallManager.getFile(name);
		if (!file.exists())
			return "File does not exist \"" + file.getPath() + "\"";
		FileInputStream fis = null;
		try {
			fis = new FileInputStream(file);
		} catch (Exception e) {
			return "IOError - " + e + ": " + e.getMessage();
		}
		
		putIntoEngine(loadObjects(fis));
		
		return null;
	}
	
	public static String writeLevel(String name) { return writeFile("levels/" + name); }
	public static String writeSave(String name) { return writeFile("saves/" + name); }
	
	public static String writeFile(String fname) {
		File file = InstallManager.getFile(fname);
		if (!file.getParentFile().exists() && !file.getParentFile().mkdirs()) {
			return "Failed to create parent directory.";
		}
		
		try {
			if (!file.exists() && !file.createNewFile()) {
				return "File does not exist.";
			}
			PrintStream ps = new PrintStream(file);
			write(ps, GameEngine.getObjects());
		} catch (Exception e) {
			return "IOError - " + e + ": " + e.getMessage();
		}
		
		
		return null;
	}
	
	public static void write(PrintStream out, Iterable<GameObject> objects) {
		for (GameObject go : objects) {
			out.println(store(go));
		}
	}
	
	public static String store(GameObject go) {
		String spawnCode = go.getClass().getName() + " ";
		spawnCode += go.generateSpawnCommand();
		spawnCode += "|" + go.left();
		spawnCode += "|" + go.top();
		spawnCode += "|" + go.width();
		spawnCode += "|" + go.height();
		spawnCode += "|" + go.vx();
		spawnCode += "|" + go.vy();
		return spawnCode;
	}
	
	public static GameObject parse(String line) {
		System.out.println(line);
		
		int space = line.indexOf(' ');
		if (space < 0) return null;
		String cname = line.substring(0, space);
		line = line.substring(space).trim();

		Method method = null;
		try {
			Class clazz = Class.forName(cname);
			method = clazz.getMethod("createObject", String.class);
		} catch (Exception e) {
			return null;
		}
		
		int bar = line.indexOf('|');
		String command = line.substring(0, bar);
		String[] params = line.substring(bar+1).split("[|]");
		
		GameObject object = null;
		
		try {
			object = (GameObject) method.invoke(null, command);
		} catch (Exception e) {
			return null;
		}

		if (params != null && params.length >= 6) {
			object.left(Double.parseDouble(params[0]));
			object.top(Double.parseDouble(params[1]));
			object.width(Double.parseDouble(params[2]));
			object.height(Double.parseDouble(params[3]));
			object.vx(Double.parseDouble(params[4]));
			object.vy(Double.parseDouble(params[5]));
		} else {
			return null;
		}
		
		return object;
	}
	
	private static void putIntoEngine(List<GameObject> ls) {
		GameEngine.clearObjects();
		for (GameObject go : ls) 
			GameEngine.addObject(go);
	}
	
	public static List<GameObject> loadObjects(InputStream sin) {
		LinkedList<GameObject> ls = new LinkedList<GameObject>();
		
		BufferedReader in = new BufferedReader(new InputStreamReader(sin));
		
		String reads = null;
		do {
			try { reads = in.readLine(); }
			catch (Exception e) {}
			
			if (reads != null) {
				GameObject go = parse(reads);
				if (go != null)
					ls.add(go);
			}
			
		} while (reads != null);
		
		return ls;
	}
}
